package chapter9;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;

/**
 * @author lzy
 * @version v1.0
 * Create DateTime: 2019/2/18 17:59
 */
public class DynamicArray<T> implements Iterable<T> {
    private static final int InitCapacity = 16;
    private int size;
    private T[] elements;
    private Class<T> tClass;

    @SuppressWarnings("unchecked")
    public DynamicArray() {
        this.tClass = gettClass();
        this.elements = (T[]) Array.newInstance(tClass, InitCapacity);
        this.size = 0;
    }

    @SuppressWarnings("unchecked")
    private Class<T> gettClass() {
        Type superClass = getClass().getGenericSuperclass();
        if (superClass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) superClass;
            Type[] args = parameterizedType.getActualTypeArguments();
            if (args != null && args.length > 0) {
                return (Class<T>) args[0];
            }
        }
        return (Class<T>) Object.class;
    }

    /**
     * 保证数组空间大小足够存放指定的数据
     * 如果不满足则扩容
     *
     * @param minCapacity
     */
    private void ensureCapacity(int minCapacity) {
        int oldCapacity = elements.length;
        if (oldCapacity > minCapacity) {
            return;
        }
        int newCapacity = oldCapacity << 1;
        if (newCapacity < minCapacity) {
            newCapacity = minCapacity;
        }
        elements = Arrays.copyOf(elements, newCapacity);
    }

    /**
     * 向动态数组中加入元素
     *
     * @param t
     */
    public void add(T t) {
        ensureCapacity(size + 1);
        elements[size++] = t;
    }

    /**
     * 获取指定索引位置的数据
     *
     * @param index
     * @return
     */
    public T get(int index) {
        return elements[index];
    }

    /**
     * 返回动态数组的大小
     *
     * @return
     */
    public int size() {
        return size;
    }

    /**
     * 修改指定位置的元素
     *
     * @param index
     * @param element
     * @return
     */
    public T set(int index, T element) {
        T oldValue = get(index);
        elements[index] = element;
        return oldValue;
    }

    /**
     * 删除指定位置的元素
     *
     * @param index
     * @return
     */
    public T remove(int index) {
        T oldValue = get(index);
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(elements, index + 1, elements, index, numMoved);
        }
        elements[--size] = null;
        return oldValue;
    }

    /**
     * 在指定索引位置加入元素
     *
     * @param index
     * @param element
     */
    public void add(int index, T element) {
        ensureCapacity(size + 1);
        System.arraycopy(elements, index, elements, index + 1, size - index);
        elements[index] = element;
        size++;
    }

    @Override
    public Iterator<T> iterator() {
        return new ArrayIterator();
    }

    public ListIterator<T> listIterator(int index) {
        return new DynamicArrayListIterator(index);
    }

    private class ArrayIterator implements Iterator<T> {
        //游标指向下一个将要访问的元素位置
        int cursor;
        //上一次迭代的元素位置
        int lastRet;

        public ArrayIterator() {
            this.lastRet = -1;
            this.cursor = 0;
        }

        @Override
        public boolean hasNext() {
            return cursor < size;
        }

        @Override
        public T next() {
            int i = cursor;
            if (i > size) {
                throw new NoSuchElementException();
            }
            cursor = i + 1;
            lastRet = i;
            return get(i);
        }

        @Override
        public void remove() {
            if (lastRet < 0) {
                throw new IllegalStateException();
            }
            ;

            DynamicArray.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
        }
    }

    private class DynamicArrayListIterator extends ArrayIterator implements ListIterator<T> {

        public DynamicArrayListIterator(int index) {
            super();
            this.cursor = index;
        }

        @Override
        public boolean hasPrevious() {
            return cursor > 0;
        }

        @Override
        public T previous() {
            if (!hasPrevious()) {
                throw new NoSuchElementException();
            }
            cursor--;
            lastRet = cursor;
            return get(lastRet);
        }

        @Override
        public int nextIndex() {
            return cursor;
        }

        @Override
        public int previousIndex() {
            return cursor - 1;
        }

        @Override
        public void set(T t) {
            if (lastRet == -1) {
                throw new IllegalStateException();
            }
            DynamicArray.this.set(lastRet, t);
        }

        @Override
        public void add(T t) {
            DynamicArray.this.add(cursor, t);
            cursor++;
            lastRet = -1;
        }
    }

}
